#include "redis.hh"
#include <iostream>
#include <thread>
#include "log/zuclog.h"

Redis::Redis() : _redisContext(nullptr)
{
    std::cout << "reidis Constructor" << std::endl;

    connect();
}

Redis::~Redis()
{
    if (_redisContext != nullptr)
    {
        std::cout << "reidis Destructor" << std::endl;
        redisFree(_redisContext);
    }
}

// 连接redis服务器
bool Redis::connect()
{
    _redisContext = redisConnect("127.0.0.1", 6379);
    if (_redisContext == nullptr || _redisContext->err)
    {
        if (_redisContext)
        {
            // handle error
            zucInnerErr("%s", _redisContext->errstr);
            return false;
        }
        else
        {
            zucInnerErr("redis error:Can't allocate redis context");
            return false;
        }
    }
    return true;
}

template <typename Value> void Redis::SETSTRING(const std::string& key, Value value)
{
    ss.clear();
    ss << value;
    std::string command;
    getline(ss, command);
    executeCommand(key, command);
    ss.str("");
}

bool Redis::executeCommand(const std::string& key, const std::string& value)
{
    redisReply* reply = (redisReply*)redisCommand(_redisContext, "HSET scriptVariables  %s  %s ", key.c_str(), value.c_str());
    if (reply == nullptr)
    {
        zucInnerErr("vars observation info:can't get variables");
        return false;
    }
    freeReplyObject(reply);
    return true;
}

// 将系统变量写入内存数据库
void Redis::storeVariable(const int& sysVarID, const double& sysVarValue) { SETSTRING(std::to_string(sysVarID), sysVarValue); }

// 将标量写入内存数据库
void Redis::storeVariable(const std::string& varName, const double& scalarVar) { SETSTRING(varName, scalarVar); }

void Redis::storeVariable(const std::string& varName, const std::string& stringVar) { SETSTRING(varName, stringVar); }

void Redis::storeVariable(const std::string& varName, const std::vector<double>& arrVar)
{
    std::string strs = "[";

    for (const double& value : arrVar)
    {
        strs += std::to_string(value);
        strs += ",";
    }

    strs[strs.size() - 1] = ']';
    SETSTRING(varName, strs);
}

// 根据变量名查询变量值
bool Redis::getVariable(varNameList& nameList, varValueMap& varValueMap)
{
    for (std::string& varName : nameList)
    {
        redisReply* reply = (redisReply*)redisCommand(_redisContext, "GET %s", varName.c_str());

        if (reply == nullptr)
        {
            std::cerr << "set command failed" << std::endl;  //FixMe
        }
        else if (reply->type == REDIS_REPLY_STRING)
        {
            varValueMap[varName] = reply->str;
        }
        // std::cout << "reply->str:" << reply->str << std::endl;
        freeReplyObject(reply);
    }

    return true;
}

// 根据变量名查询变量值
bool Redis::getKeyValue(const std::string& key, std::string& value)
{
    redisReply* reply = (redisReply*)redisCommand(_redisContext, "GET %s ", key.c_str());
    if (reply == nullptr)
    {
        // zucLogInfo(2, "[redis] get :can't get variables");
        return false;
    }
    else if (reply->type == REDIS_REPLY_STRING)
    {
        value = reply->str;
    }
    else
    {
        // zucLogInfo(2, "[redis] get :can't get variables, reply.type:%d\n",reply->type);
    }
    freeReplyObject(reply);
    return true;
}

bool Redis::storeStringVariable(const std::string& varName, const std::string& varValue)
{
    redisReply* reply = (redisReply*)redisCommand(_redisContext, "HSET ss %s %s", varName.c_str(), varValue.c_str());
    if (reply == nullptr)
    {
        std::cerr << "set command failed" << std::endl;
        return false;
    }
    freeReplyObject(reply);
    return true;
}